package com.fumin.service;

import com.fumin.common.RequestHolder;
import com.fumin.dao.SysDeptMapper;
import com.fumin.dao.SysUserMapper;
import com.fumin.exception.ParamException;
import com.fumin.model.SysDept;
import com.fumin.param.DeptParam;
import com.fumin.util.BeanValidator;
import com.fumin.util.IpUtil;
import com.fumin.util.LevelUtil;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @Author xiayuxuanmin
 * @Date 2019/10/21
 * @Description
 */
@Service
public class SysDeptService {

    //默认@Autowired是按类型type自动注入
    //默认@Resource是按名字byName自动注入，也可以指定type注入
    @Resource
    private SysDeptMapper sysDeptMapper;
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysLogService sysLogService;

    /**
     * 新增部门
     * @param param
     */
    public void save(DeptParam param) {
        BeanValidator.check(param);//检测参数是否合法
        if (checkExist(param.getParentId(), param.getName(), param.getId())) {
            throw new ParamException("同一层级下存在相同名称的部门!");
        }
        SysDept sysDept = SysDept.builder().name(param.getName()).parentId(param.getParentId())
                .seq(param.getSeq()).remark(param.getRemark()).build();
        sysDept.setLevel(LevelUtil.calculateLevel(getLevel(param.getParentId()), param.getParentId()));
        sysDept.setOperator(RequestHolder.getCurrentUser().getUsername());//TODO:
        sysDept.setOperateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest()));//TODO:
        sysDept.setOperateTime(new Date());
        sysDeptMapper.insertSelective(sysDept);//insert和insertSelective的区别:insertSelective只插入有值的属性...
        sysLogService.saveDeptLog(null,sysDept);
    }

    /**
     * 更新部门
     * @param param
     */
    public void update(DeptParam param) {
        BeanValidator.check(param);//检测参数是否合法
        if (checkExist(param.getParentId(), param.getName(), param.getId())) {
            throw new ParamException("同一层级下存在相同名称的部门!");
        }
        SysDept before = sysDeptMapper.selectByPrimaryKey(param.getId());
        Preconditions.checkNotNull(before, "待更新的部门不存在！");
        SysDept after = SysDept.builder().id(param.getId()).name(param.getName()).parentId(param.getParentId())
                .seq(param.getSeq()).remark(param.getRemark()).build();
        after.setLevel(LevelUtil.calculateLevel(getLevel(param.getParentId()), param.getParentId()));
        after.setOperator(RequestHolder.getCurrentUser().getUsername());
        after.setOperateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest()));
        after.setOperateTime(new Date());
        updateWithChild(before, after);
        sysLogService.saveDeptLog(before,after);
    }

    /**
     * 更新部门的所有下级子孙级部门的LEVEL
     * @param before 更新前的记录
     * @param after  更新后的记录
     */
    @Transactional //添加事务，在修改子孙级部门的时候，要么一起成功，要么一起失败
    public void updateWithChild(SysDept before, SysDept after) {
        String newLevelPrefix = after.getLevel();
        String oldLevelPrefix = before.getLevel();
        if (!newLevelPrefix.equals(oldLevelPrefix)) {
            //如果更新了部门的LEVEL（LEVEL不同，那么需要更新子孙级部门的LEVEL）
            List<SysDept> deptList = sysDeptMapper.getChildDeptListByLevel(before.getLevel());
            List<SysDept> updateList = Lists.newArrayList();
            if (CollectionUtils.isNotEmpty(deptList)) {
                for (SysDept dept : deptList) {
                    String level = dept.getLevel();
                    //level.equals(oldLevelPrefix+"."+before.getId())为子节点
                    // level.indexOf(oldLevelPrefix+"."+before.getId()+".") == 0 为孙子节点
                    if (level.equals(oldLevelPrefix+"."+before.getId()) || level.indexOf(oldLevelPrefix+"."+before.getId()+".") == 0) {//如果是当前改变节点的子孙节点
                        //例如:原来为1.3.1,父节点level为1.3,父节点ID为1,现在改为:1.4,加上父节点ID为1,所以新的LEVEL为:1.4.1
                        //newLevelPrefix为1.4,即新的父节点LEVEL,level为1.3.1,oldLevelPrefix父节点原来的LEVEL为1.3;
                        ///所以以新的父节点LEVEL加上移除掉老的父节点LEVEL的部分level.substring(oldLevelPrefix.length())即可
                        level = newLevelPrefix + level.substring(oldLevelPrefix.length());
                        dept.setLevel(level);
                        updateList.add(dept);
                    }
                }
                sysDeptMapper.batchUpdateLevel(updateList);
            }
        }
        sysDeptMapper.updateByPrimaryKey(after);
    }

    /**
     * 判断同一个部门下是否有重复的子部门
     * @param parentId
     * @param deptName
     * @param deptId
     * @return
     */
    private boolean checkExist(Integer parentId, String deptName, Integer deptId) {
        return sysDeptMapper.countByNameAndParentId(parentId, deptName, deptId) > 0;
    }

    /**
     * 获取指定的部门的层级
     * @param deptId 部门ID
     * @return
     */
    public String getLevel(Integer deptId) {
        SysDept sysDept = sysDeptMapper.selectByPrimaryKey(deptId);
        if (sysDept == null) {
            return null;
        }
        return sysDept.getLevel();
    }

    public void delete(int deptId){
        SysDept dept = sysDeptMapper.selectByPrimaryKey(deptId);
        Preconditions.checkNotNull(dept,"待删除的部门不存在,无法删除!");
        if (sysDeptMapper.countByParentId(dept.getId()) > 0) {
            throw new ParamException("当前部门下有子部门,无法删除!");
        }
        if (sysUserMapper.countByDeptId(dept.getId()) > 0) {
            throw new ParamException("当前部门下有用户,无法删除!");
        }
        sysDeptMapper.deleteByPrimaryKey(dept.getId());
    }
}
